发布在网络上,权当备份,程序还未完成。。。
使用的是Air724作为4G数据透传
插座上使用ESP32作为客户端,air724与esp32通信使用的是hc-12
有一个小小的缺点,就是使用hc-12发数据时会丢包,不知道有么有小伙伴有更好的解决办法~~
贴上未完成的程序代码,写的程序比较拉跨,勿喷~以下是4g透传模块的程序:
main.lua:
PROJECT = "CLIENT" VERSION = "1.0.0" require "sys" require 'study' --启动系统框架 sys.init(1, 0) sys.run()
study.lua:
module(..., package.seeall) require 'sys' require 'mqtt' require 'log' require 'audio' require 'pm' require 'socket' require 'uart' require 'net' local UART_ID = 1 local uartData = nil local mqttClient = nil local mqttUsername = '10001' local mqttPort = 1883 local mqttAddress = 'xxx.cn1.mqtt.chat' local mqttPassword = 'xxx' local mqttClientId = 'xxx@xxx' local mqttPublish = 'julecn/esp32/recv' local mqttSubscribe = 'julecn/esp32/data' local function uartRead() local data = '' --底层core中,串口收到数据时: --如果接收缓冲区为空,则会以中断方式通知Lua脚本收到了新数据; --如果接收缓冲器不为空,则不会通知Lua脚本 --所以Lua脚本中收到中断读串口数据时,每次都要把接收缓冲区中的数据全部读出, --这样才能保证底层core中的新数据中断上来,此read函数中的while语句中就保证了这一点 while true do data = uart.read(UART_ID,999999999) if not data or string.len(data) == 0 then break end log.info("read Data:",data) uartData = data end end -- local function uartWrite(s) -- uart.write(UART_ID,s.."\r\n") -- end local function uartWriteOk() log.info('uartWriteOk') end function uartInit() sys.wait(5000) uart.on(UART_ID,"sent",uartWriteOk) uart.on(UART_ID,"receive",uartRead) uart.setup(UART_ID,115200,8,uart.PAR_ODD,uart.STOP_1,nil,1) end function getMessage() while true do local r, data, param = mqttClient:receive(10, "pub_msg") if r and data.payload then -- uartWrite(data.payload) uart.write(UART_ID,data.payload.."\r\n") log.info("subscribe:", data.payload or "nil") elseif data == "pub_msg" then log.info("这是收到了订阅的消息和参数显示:", data, param) elseif data == "timeout" then -- log.info("这是等待超时主动上报数据的显示!") if uartData then log.info("publish data:",uartData) mqttClient:publish('julecn/esp32/recv',uartData,0) uartData = nil end else log.info('连接断开,重启中……',r,data,param) sys.restart('MQTT断开,触发重启') break end end end function subscribe() log.info('正在订阅消息') sys.wait(100) if mqttClient:subscribe("julecn/esp32/data", 1) then log.info('消息订阅成功') getMessage() else log.info('消息订阅失败') connect() end end function connect() local err = 0 while not socket.isReady() do log.info('网络未就绪,等待中…') log.info(net.getNetMode()) log.info(net.getState()) err = err + 1 if err >= 45 then sys.restart('网络无法连接,触发重启') end sys.wait(1000) end log.info('初始化已完成,准备连接网络') sys.wait(5000) mqttClient = mqtt.client(mqttClientId,60,mqttUsername,mqttPassword) while true do if mqttClient:connect(mqttAddress,mqttPort,"tcp") then log.info('网络连接成功') sys.wait(100) subscribe() break; else log.info('网络连接失败,重启中…') sys.restart('网络连接失败,触发重启') end end end function start() sys.taskInit(uartInit) sys.taskInit(connect) end sys.timerStart(function() start() end,5000)
插座的使用的ESP32:
boot.py
from machine import UART import time import json from jule import app import _thread # 4、15 上级接口 # 22、23 下级接口 def start(): app.p = UART(1, baudrate = 115200, bits = 8, parity = None, rx = 4, tx = 15, timeout = 10,stop = 1) try: app.start() print('service start…') while app.ISRUNING(): if(app.p.any()): rs = app.uartProcessor(app.p.read()) if(isinstance(rs,dict)): app.p.write(json.dumps(rs)) print('回复数据:{}'.format(rs)) except KeyboardInterrupt: print('中断执行') except Exception as e: print(e) start()
jule.py
import os import re import sys import json import time import upip import array import socket import struct import network import _thread import ubluetooth from machine import Timer,UART from machine import PWM, Pin from umqtt.simple import MQTTClient class ble: UART_UUID = ubluetooth.UUID("6E400001-B5A3-F393-E0A9-E50E24DCCA9E") RX_UUID = ubluetooth.UUID("6E400002-B5A3-F393-E0A9-E50E24DCCA9E") TX_UUID = ubluetooth.UUID("6E400003-B5A3-F393-E0A9-E50E24DCCA9E") _ADV_TYPE_FLAGS = const(0x01) _ADV_TYPE_NAME = const(0x09) _ADV_TYPE_UUID16_COMPLETE = const(0x3) _ADV_TYPE_UUID32_COMPLETE = const(0x5) _ADV_TYPE_UUID128_COMPLETE = const(0x7) _ADV_TYPE_UUID16_MORE = const(0x2) _ADV_TYPE_UUID32_MORE = const(0x4) _ADV_TYPE_UUID128_MORE = const(0x6) _ADV_TYPE_APPEARANCE = const(0x19) _IRQ_CENTRAL_CONNECT = const(1 << 0) #中央设备已经连接到这个外围设备 _IRQ_CENTRAL_DISCONNECT = const(1 << 1) #中央设备已与此外围设备断开 _IRQ_GATTS_WRITE = const(1 << 2) #中央设备已写入此特征或描述符 _IRQ_GATTS_READ_REQUEST = const(1 << 3) # 中央设备已发出读请求. # Note: 这是一个硬件IRQ,返回None来拒绝读操作 ¥ # Note: 这事件不支持 ESP32. _IRQ_SCAN_RESULT = const(1 << 4) #一次扫描的结果 _IRQ_SCAN_COMPLETE = const(1 << 5) #扫描持续时间已完成或手动停止 _IRQ_PERIPHERAL_CONNECT = const(1 << 6) #gap_connect()连接成功 _IRQ_PERIPHERAL_DISCONNECT = const(1 << 7) #已连接的外围设备已断开 _IRQ_GATTC_SERVICE_RESULT = const(1 << 8) #调用gattc_discover_services()找到的每个服务 _IRQ_GATTC_CHARACTERISTIC_RESULT = const(1 << 9) #调用gattc_discover_services()找到的每个特征 _IRQ_GATTC_DESCRIPTOR_RESULT = const(1 << 10) #调用gattc_discover_descriptors()找到的每个描述符 _IRQ_GATTC_READ_RESULT = const(1 << 11) #gattc_read() 已完成 _IRQ_GATTC_WRITE_STATUS = const(1 << 12) #gattc_write() 已完成 _IRQ_GATTC_NOTIFY = const(1 << 13) #外围设备已发出通知请求 _IRQ_GATTC_INDICATE = const(1 << 14) #外围设备发出指示请求 UART_SERVICE = ( UART_UUID,( (TX_UUID, ubluetooth.FLAG_NOTIFY,), (RX_UUID, ubluetooth.FLAG_WRITE,), ), ) def __init__(self,name = 'JULE-IOT'): self._bt = ubluetooth.BLE() self.conn_handle = None self.write = self._bt.gatts_write self.read = self._bt.gatts_read self.notify = self._bt.gatts_notify self._bt.active(False) print("activating ble...") self._bt.active(True) print("ble activated") self._bt.config(rxbuf = rxbuf) self._bt.irq(self.irq) self.register_services() self.adv_payload = self.advertising_payload(name = name, services = (self.UART_UUID), appearance = const(768)) self.advertise() def advertising_payload(self,limited_disc = False, br_edr = False, name = None, services = None, appearance = 0): payload = bytearray() def _append(adv_type, value): nonlocal payload payload += (struct.pack('BB', len(value) + 1, adv_type) + value) _append(const(0x01), struct.pack('B', (0x01 if limited_disc else 0x02) + (0x00 if br_edr else 0x04))) if name: _append(const(0x09), name) _append(_ADV_TYPE_APPEARANCE, struct.pack('<h', appearance)) return payload def advertise(self, interval_us = 500000): self._bt.gap_advertise(None) self._bt.gap_advertise(interval_us, adv_data = self.adv_payload, resp_data = None) print("advertising...") def register_services(self): ((self.tx_handle,self.rx_handle,),) = self._bt.gatts_register_services((self.UART_SERVICE,)) def irq(self,event,data): if event == _IRQ_CENTRAL_CONNECT: self.__conn_handle, addr_type, addr = data print('已连接:{}'.format(data)) elif event == _IRQ_CENTRAL_DISCONNECT: print('中央设备已与此外围设备断开') conn_handle, addr_type, addr = data self.__advertise() # elif event == _IRQ_GATTS_WRITE: elif event == 3: conn_handle, value_handle = data read = self.__read(self.__rx_handle).decode('utf-8') print('中央设备已写入此特征或描述符:{}'.format(read)) # if conn_handle == self.__conn_handle and value_handle == self.__rx_handle: elif event == _IRQ_GATTS_READ_REQUEST: print('中央设备已发出读请求') conn_handle, attr_handle = data elif event == _IRQ_SCAN_RESULT: print('一次扫描的结果') addr_type, addr, connectable, rssi, adv_data = data elif event == _IRQ_SCAN_COMPLETE: print('扫描持续时间已完成或手动停止') elif event == _IRQ_PERIPHERAL_CONNECT: print('gap_connect()连接成功') conn_handle, addr_type, addr = data elif event == _IRQ_PERIPHERAL_DISCONNECT: print('已连接的外围设备已断开') conn_handle, addr_type, addr = data elif event == _IRQ_GATTC_SERVICE_RESULT: print('调用gattc_discover_services()找到的每个服务') conn_handle, start_handle, end_handle, uuid = data elif event == _IRQ_GATTC_CHARACTERISTIC_RESULT: print('调用gattc_discover_services()找到的每个特征') conn_handle, def_handle, value_handle, properties, uuid = data elif event == _IRQ_GATTC_DESCRIPTOR_RESULT: print('调用gattc_discover_descriptors()找到的每个描述符') conn_handle, dsc_handle, uuid = data elif event == _IRQ_GATTC_READ_RESULT: print('gattc_read() 已完成') conn_handle, value_handle, char_data = data elif event == _IRQ_GATTC_WRITE_STATUS: print('gattc_write() 已完成') conn_handle, value_handle, status = data elif event == _IRQ_GATTC_NOTIFY: print('外围设备已发出通知请求') conn_handle, value_handle, notify_data = data elif event == _IRQ_GATTC_INDICATE: print('外围设备发出指示请求') conn_handle, value_handle, notify_data = data else: print(event,data) class config: __default = { 'wifi':{ 'ssid':'JULE-IOT', 'password':'12345678', 'active':True }, 'mqtt':{ 'autoConnect':False, 'clientId':None, 'server':None, 'user':None, 'passsword':None, 'keeplive':60, 'ssl':False, 'ssl_params':{}, 'subscribe':[] } } __config = {} def __init__(self): try: os.mkdir('/config') except: pass # 读取文件合并数据 for i in os.listdir('/config'): if i.endswith('.ini') == False: continue filename = i.rstrip('ini').rstrip('.') try: file = open('/config/' + i,'r') conf = json.loads(file.read()) config.__config[filename] = conf file.close() except: default = {} if filename in config.__default: default = config.__default[filename] file = open('/config/' + i,'w') file.write(json.dumps(default)) file.close() print('合并默认配置',filename) # 保存默认配置信息 for i in config.__default: if i not in config.__config: try: file = open('/config/' + i + '.ini','w') file.write(json.dumps(config.__default[i])) file.close() config.__config[i] = config.__default[i] except Exception as e: print('保存默认配置异常',e) print('config info:{}'.format(config.__config)) def get(self,key,default = None): if key == None: return config.__config key = key.split('.',2) try: file = open('/config/' + key[0] + '.ini','r') v = json.loads(file.read()) config.__config[key[0]] = v file.close() if len(key) == 2 and key[1] in v: return v[key[1]] else: return v except: return default def set(self,key,value): key = key.split('.',2) try: if len(key) == 2: config.__config[key[0]][key[1]] = value else: config.__config[key[0]] = value file = open('/config/' + key[0] + '.ini','w') file.write(json.dumps(config.__config[key[0]])) file.close() return True except Exception as e: print('系统文件异常',e) def delete(self,key): key = key.split('.',2) try: if len(key) == 2 and key[0] in config.__config: del config.__config[key[0]][key[1]] file = open('/config/' + key[0] + '.ini','w') file.write(json.dumps(config.__config[key[0]])) file.close() else: del config.__config[key[0]] try: os.remove('/config/' + key[0] + '.ini') except: pass return True except Exception as e: print('删除文件配置异常',e) class system: def __init__(self): pass def error(self,data): pass class device: def __init__(self): pass def __getattribute__(self, name): pass def __setattr__(self, name, value): pass def __delattr__(self, name): pass def factoryReset(self,data): print('factory reset...') try: os.rmdir('/config') except Exception as e: pass print('reboot...') self.reboot(data) def reboot(self,data): import machine machine.reset() def sub(self,data): print(data) app.subDevice.write(json.dumps(data)) def scanWifi(self,data): app.wlan = network.WLAN(network.STA_IF) app.wlan.active(True) scan = app.wlan.scan() print('SCAN WIFI:{}'.format(scan)) response = {"action":"device.scanWifi","data":scan} return response def info(self,data): print('WIFI IP:{}'.format(app.wlan.ifconfig()[0])) response = {"action":"device.info","data":{"vlan_wifi":app.wlan.ifconfig()[0]}} return response def wlanStatus(self,data): status = app.wlan.status() print('wlan status:{}'.format(status)) return {"action":"device.wlanStatus","data":{"status":status}} def wlanInfo(self,data): ip,subnet_mask,gateway,dns = app.wlan.ifconfig() return {'action':'device.wlanInfo','data':{'ip':ip,'subnet_mask':subnet_mask,'gateway':gateway,'dns':dns}} def exit(self,data): sys.exit() app.__ISRUNING = False print('sys stop!') def connectWifi(self,data): if "ssid" not in data or 'password' not in data: return {"action":"device.connectwifi",'data':{'code':-1,'msg':'SSID或Password不存在'}} reset = False if "reset" in data and data['reset'] : reset = True ret,wlan = app.connectWifi(data['ssid'], data['password'],reset) resp = { "action":"device.connectWifi", "data":{ "wlan_info":app.wlan.ifconfig(), 'wlan_status':app.wlan.status() } } if ret: resp['code'] = 1 else: resp['code'] = -1 return resp class gpio: def __init__(self): self.pins = { 'pwm':[0,2,5,10,12,13,14,18,19,21,25,27,28,29,33], 'i2c':[0,2,4,5,9,18,19,21,25,26,27], 'switch':[13,12,14,27,26,25,33,32,2,16,17,5,18,19,21,] } def pwm(self,data): if "duty" in data and "pin" in data and data["pin"] in self.pins['pwm']: freq = 78125 if "freq" in data: freq = data["freq"] if freq > 78125: freq = 78125 pwm = PWM(Pin(data["pin"]), freq = freq, duty = data["duty"]) print('pin:{},duty:{},freq:{}'.format(data['pin'],data["duty"],freq)) return {'code':1,'action':'gpio.pwm','data':{'status':1}} else: print('no pins') return {'code':1,'action':'gpio.pwm','data':{'status':-1,'msg':'no pins or duty'}} def i2c(self,data): pass def switch(self,data): if "switch" in data and "pin" in data and data["pin"] in self.pins['switch']: switch = True if not data['switch']: switch = False p = Pin(data['pin'],Pin.OUT) p.value(switch) def NecIR(self,data): pass class bt: pass class mqtt: def __init__(self): self.__status = False def init(self,data): resp = {'code':1,'action':'mqtt.init','data':{'status':-1,'msg':''}} if 'clientId' not in data: resp['data']['msg'] = 'not clientId' return resp if 'server' not in data: resp['data']['msg'] = 'not server' return resp port,user,password,keepalive,ssl,ssl_params = 0,None,None,60,False,{} clientId = data['clientId'] server = data['server'] if 'user' in data:user = data['user'] if 'password' in data:password = data['password'] if 'keepalive' in data:keepalive = data['keepalive'] if 'ssl' in data:ssl = data['ssl'] if 'ssl_params' in data:ssl_params = data['ssl_params'] self.__client = MQTTClient(clientId,server,port,user,password,keepalive,ssl,ssl_params) def connect(self,data): try: self.__client.connect() except Exception as e: print('MQTT connection error:',e) return {'code':1,'action':'mqtt.connect','data':{'status':-1,'msg':e}} def status(self,data): return self.__status def close(self,data): self.__client.disconnect() print('MQTT closed') def ping(self,data): self.__client.ping() print('MQTT ping') def publish(self,data): resp = {'code':1,'action':'mqtt.publish','data':{'status':-1,'msg':''}} if 'topic' not in data: resp['data']['msg'] = 'miss param:topic' return resp if 'msg' not in data: resp['data']['msg'] = 'miss param:msg' return resp retain,qos = False,0 if 'retain' in data and isinstance(data['retain'], bool): retain = data['reatain'] if 'qos' in data and isinstance(data['qos'], int): qos = data['qos'] self.__client.publish(data['topic'],data['msg'],retain,qos) def subscribe(self,data): resp = {'code':1,'action':'mqtt.subscribe','data':{'status':-1,'msg':''}} if 'topic' not in data: resp['data']['msg'] = 'miss param:topic' return resp qos = 0 if 'qos' in data and isinstance(data['qos'], int):qos = data['qos'] self.__client.subscribe(data['topic'],qos) def processor(): def cb(topic,msg): try: msg = json.loads(msg) except: msg = {} print(topic,msg) app.module['mqtt'].__client.set_callback(cb) def msg(): t = time.time() try: while app.__ISRUNING: print(app.__ISRUNING) app.module['mqtt'].__status = True app.module['mqtt'].__client.check_msg() if time.time() - t + 1 >= app.module['mqtt'].__client.keepalive: t = time.time() app.module['mqtt'].ping({}) time.sleep(0.1) app.module['mqtt'].close({}) except Exception as e: print('MQTT ERROR:',e) app.module['mqtt'].__status = False if app.config.get('mqtt.autoReconnect',False) == True: print('MQTT reconnect...') time.sleep(1) app.mqttConnect() _thread.start_new_thread(msg,()) class app: p = None wlan = None __ISRUNING = False config = config() module = { 'device':device(), 'gpio':gpio(), 'bt':bt(), 'system':system(), 'mqtt':mqtt() } def start(): app.__ISRUNING = True if app.config.get('subdevice.enabled',False): rx = app.config.get('subdevice.rx',22) rx = app.config.get('subdevice.tx',23) app.subDevice = UART(2, baudrate = 115200, bits = 8, parity = None, rx = rx, tx = tx, timeout = 10,stop = 1) def subDeviceRecv(): try: while app.ISRUNING(): if(app.subDevice.any()): read = json.loads(app.subDevice.read()) if(isinstance(read,dict)): app.p.write(json.dumps(read)) print('子设备回复:{}'.format(read)) except KeyboardInterrupt: print('中断执行') except Exception as e: print(e) _thread.start_new_thread(subDeviceRecv, ()) app.wlan = network.WLAN(network.STA_IF) ssid = app.config.get('wifi.ssid') password = app.config.get('wifi.password') active = app.config.get('wifi.active',False) if ssid and password and active == True: app.connectWifi(ssid, password) if app.wlan.status() == 1010: app.mqttConnect() def mqttConnect(): try: mqttConfig = app.config.get('mqtt',None) if mqttConfig and mqttConfig['autoConnect'] == True: app.module['mqtt'].init(mqttConfig) app.module['mqtt'].connect({}) mqtt.processor() for i in mqttConfig['subscribe']: app.module['mqtt'].subscribe({'topic':i}) except Exception as e: print('MQTT exception',e) def isEsp32(): uname = getattr(os,'uname',None) if uname == None:return False sysname,nodename,release,version,machine = uname() return sysname == "esp32" def ISRUNING(): return app.__ISRUNING def msgProcessor(topic,msg): print('topic:{}'.format(topic)) try: data = json.loads(msg) except: data = {} print('msg:{}'.format(data)) if 'action' in data and re.match(r'^([a-zA-Z])+\.(\w)+$',data['action']): action = data['action'].split('.') if action[0] not in app.module: print('[{}]模块不支持!'.format(action[0])) else: func = getattr(app.module[action[0]],action[1],None) if not func: print('[{}]操作不支持!'.format(action[1])) else: getData = {} if 'data' in data and isinstance(data['data'],dict): getData = data['data'] func(getData) def uartProcessor(origin): try: data = json.loads(origin) print('msg:{}'.format(data)) except: print('data:{}'.format(origin)) data = {} if 'action' in data and re.match(r'^([a-zA-Z])+\.(\w)+$',data['action']): action = data['action'].split('.') if action[0] not in app.module: return {"action":"system.error","data":{"msg":'[{}]模块不支持!'.format(action[0])}} func = getattr(app.module[action[0]],action[1],None) if not func: return {"action":"system.error","data":{"msg":'[{}]操作不支持!'.format(action[1])}} getData = {} if 'data' in data and isinstance(data['data'],dict): getData = data['data'] resp = func(getData) if isinstance(resp,dict) and 'req_id' in data: resp['req_id'] = data['req_id'] return resp def connectWifi(ssid, password,reset = False): # STAT_IDLE -- 没有连接,没有活动-1000 # STAT_CONNECTING -- 正在连接-1001 # STAT_WRONG_PASSWORD -- 由于密码错误而失败-202 # STAT_NO_AP_FOUND -- 失败,因为没有接入点回复,201 # STAT_GOT_IP -- 连接成功-1010 # STAT_ASSOC_FAIL -- 203 # STAT_BEACON_TIMEOUT -- 超时-200 # STAT_HANDSHAKE_TIMEOUT -- 握手超时-204 if not app.isEsp32(): print('IS NOT ESP32') return True,app.wlan if app.wlan == None: app.wlan = network.WLAN(network.STA_IF) app.wlan.active(True) if not app.wlan.isconnected() or reset: app.wlan.disconnect() app.wlan.active(True) app.wlan.connect(ssid,password) err_code = [200,201,202,203,204] if app.wlan.status() in err_code: print('WIFI connection error') return False,app.wlan elif app.wlan.status() == 1001: print('WIFI connection...') return False,app.wlan elif app.wlan.status() == 1010: print('WIFI connection success') ip,subnet_mask,gateway,dns = app.wlan.ifconfig() print('WIFI IP:{},MASK:{},GATEWAY:{},DNS:{}'.format(ip,subnet_mask,gateway,dns)) return True,app.wlan else: print('WIFI status unknown') return False,app.wlan def exit(): app.__ISRUNING = False print('exit') sys.exit() __all__ = ['app','device','gpio','config','system']
还有部分程序来自GitHub开源程序,分别是:MicroWebSrv、MicroWebTemplate、MicroWebSocket,在网上都能找到,这里就不贴了。
程序未完善,权当记录一下过程,勿喷~